package com.zjhn.ds.netty;

import com.alibaba.fastjson.JSONObject;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.net.InetSocketAddress;
import java.util.Map;

/**
 * @BelongsProject: ds_jlw
 * @BelongsPackage: com.zjhn.ds.netty
 * @Author: sxt
 * @CreateTime: 2023-09-20  08:55
 * @Description: Netty服务启动后获取到配置参数，监听配置相对应的端口
 * @Version: 1.0
 */
@Slf4j
@Component
public class NettyServer {

    @Resource
    private PortDefinition portDefinition;

    ChannelFuture future = null;

    NioEventLoopGroup boss = null;

    NioEventLoopGroup worker = null;

    ServerBootstrap bootstrap = new ServerBootstrap();

    public void start() {
        boss = new NioEventLoopGroup();
        worker = new NioEventLoopGroup();
        //1.绑定group
        bootstrap.group(boss, worker)
                //2.设置并绑定Reactor线程池：EventLoopGroup，EventLoop就是处理所有注册到本线程的Selector上面的Channel
                .channel(NioServerSocketChannel.class)
                //3.保存连接数
                .option(ChannelOption.SO_BACKLOG, 1024)
                //4.有数据立即发送
                //.option(ChannelOption.SO_SNDBUF, 4 * 1024)
                //.option(ChannelOption.SO_RCVBUF, 4 * 1024)
                .handler(new LoggingHandler(LogLevel.INFO))
                //5.保持连接
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                //6.handler作用于boss -- childHandler作用于worker
                .childHandler(new SocketChannelInitHandler(portDefinition.getPort()));

        Map<Integer, String> ports = portDefinition.getPort();
        log.info("====[INFO]========NettyServer====start netty服务器在{}端口启动监听", JSONObject.toJSONString(ports));
        try {
             /*
               绑定多个端口核心代码
             */
            for (Map.Entry<Integer, String> p : ports.entrySet()) {
                final int port = p.getKey();
                // 绑定端口
                ChannelFuture future1 = bootstrap.bind(new InetSocketAddress(port)).sync();
                future1.addListener(future -> {
                    if (future.isSuccess()) {
                        log.info("====[INFO]========NettyServer====start netty 启动成功，端口：{}", port);
                    } else {
                        log.info("====[INFO]========NettyServer====start netty 启动失败，端口：{}", port);
                    }
                });
                future1.channel().closeFuture().addListener((ChannelFutureListener) channelFuture -> future1.channel().close());
            }
        } catch (Exception e) {
            log.error("====[INFO]========NettyServer====start netty 启动时发生异常-------{}", e.getMessage());
        }
    }

    @PreDestroy
    public void stop() {
        if (future != null) {
            future.channel().close().addListener(ChannelFutureListener.CLOSE);
            future.awaitUninterruptibly();
            boss.shutdownGracefully();
            worker.shutdownGracefully();
            future = null;
            log.info("====[INFO]========NettyServer====stop  netty服务关闭");
        }
    }

}
